package ift605.EquationWithTrainingAgents.agent;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ift605.EquationWithTrainingAgents.behavior.common.VerificationBehavior;
import ift605.EquationWithTrainingAgents.struct.DerivationInfo;
import ift605.EquationWithTrainingAgents.struct.LearningMessage;
import ift605.EquationWithTrainingAgents.struct.PendingRequest;
import jade.core.Agent;
import jade.core.behaviours.Behaviour;
import jade.core.behaviours.CyclicBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;

public class PoolAgent extends Agent{
	protected static final long serialVersionUID = 1L;
	// DF basic pool agent type ID
	public static final String POOL_AGENT_DF = "PoolAgent";
	
	// Invalid request range to limit equation research propagation
	protected List<Integer> mInvalidRequest;
	protected static final int MAX_INVALID_SIZE = 200;
	
	public Map<String, DerivationInfo> mInProgess;
	
	public Map<Integer, List<PendingRequest>> mEquationChunk;
	
	protected int mNextMessId;
	
	public void setup()
	{
		super.setup();
		try {
			mInvalidRequest = new ArrayList<Integer>();
			//mKnownDerivation = new HashMap<String, List<AID>>();
			mInProgess = new HashMap<String, DerivationInfo>();
			mEquationChunk = new HashMap<Integer, List<PendingRequest>>();
			
			//Register the agent to the DIRECTORY FOLDER
			DFAgentDescription dfd = new DFAgentDescription();
			dfd.setName(getAID());
			ServiceDescription sd = new ServiceDescription();
			sd.setType(POOL_AGENT_DF);
			sd.setName(POOL_AGENT_DF);
			
			dfd.addServices(sd);
			DFService.register(this, dfd);
		} catch (FIPAException e) {
			e.printStackTrace();
		}
		
		//addBehaviour(new RegisteringBehavior());
		addBehaviour(new VerificationBehavior());
		addBehaviour(new UpdateInvalidRequestRangeBehaviour());
		
		Object[] obj = getArguments();
		
		if(obj.length > 1)
		{
			addBehaviour((Behaviour)obj[0]);
			addBehaviour((Behaviour)obj[1]);
		}
	}
	
	public boolean isValidPerformative(int aPerformative){
		return !mInvalidRequest.contains(aPerformative);
	}
	

	protected void takeDown() {
		try {
			DFService.deregister(this);
		} catch (FIPAException e) {
			e.printStackTrace();
		}
	}

	protected class UpdateInvalidRequestRangeBehaviour extends CyclicBehaviour{
		private static final long serialVersionUID = 1L;

		@Override
		public void action() {
			MessageTemplate mt = MessageTemplate.MatchConversationId(LearningMessage.UPDATE_RANGE);
			ACLMessage request = receive(mt);
			if(request != null){
				try {
					LearningMessage msg = (LearningMessage) request.getContentObject();
					
					mt = MessageTemplate.MatchPerformative(msg.requestID);
					while(request != null){
						request = receive(mt);
					}
					
					mInvalidRequest.add(msg.requestID);
					if(mInvalidRequest.size() > MAX_INVALID_SIZE){
						mInvalidRequest.remove(0);
					}
					
				} catch (UnreadableException e) {
					e.printStackTrace();
				}
			}
			else
			{
				block();
			}
		}
	}
	
	public static void AddAIDFromDF(String aDfSignature, ACLMessage mess, Agent myAgent) throws FIPAException
	{
		// Look at DF to find all PoolAgent
		DFAgentDescription dfd = new DFAgentDescription();
		ServiceDescription sd = new ServiceDescription();
		sd.setType(aDfSignature);
		sd.setName(aDfSignature);
		dfd.addServices(sd);
		DFAgentDescription[] desc = DFService.search(myAgent, dfd);
		
		if(desc.length == 0)
		{
			System.out.println("not normal....");
		}
		
		for(DFAgentDescription agent : desc){
			mess.addReceiver(agent.getName());
		}
	}
}
